<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>类目归纳审核</title>
  <style>
    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; margin: 24px; }
    h1 { font-size: 20px; margin: 0 0 12px; }
    .toolbar { display: flex; gap: 12px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
    input[type="number"], input[type="text"], textarea { padding: 6px 8px; border: 1px solid #d0d7de; border-radius: 6px; font-size: 14px; }
    button { padding: 6px 12px; border: 1px solid #1b74e4; background: #1b74e4; color: #fff; border-radius: 6px; cursor: pointer; font-size: 14px; }
    button.secondary { background: #fff; color: #1b74e4; }
    button:disabled { opacity: 0.6; cursor: not-allowed; }
    .muted { color: #666; font-size: 13px; }
    .counter { margin-left: 6px; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid #e5e7eb; padding: 8px; vertical-align: top; }
    th { background: #f8fafc; text-align: left; }
    .kw { width: 220px; }
    .code { width: 120px; }
    .name { width: 200px; }
    .def { min-width: 280px; }
    .row-actions { white-space: nowrap; }
    .chip { display: inline-block; padding: 2px 6px; border-radius: 12px; background: #eef2ff; color: #3730a3; margin: 0 4px 4px 0; font-size: 12px; }
    .notice { margin: 12px 0; padding: 10px; border: 1px solid #e5e7eb; background: #fafafa; border-radius: 6px; }
  </style>
  <script>
    async function runBuild() {
      const size = document.getElementById('sampleSize').value;
      setLoading(true);
      try {
        const url = size ? `/api/taxonomy/build?sampleSize=${encodeURIComponent(size)}` : '/api/taxonomy/build';
        const res = await fetch(url, { method: 'POST' });
        if (!res.ok) throw new Error('调用 /api/taxonomy/build 失败');
        const data = await res.json();
        document.getElementById('inserted').textContent = data.inserted ?? 0;
        renderPreview(data.preview || []);
      } catch (e) {
        alert(e.message || e);
      } finally {
        setLoading(false);
      }
    }

    function renderPreview(items) {
      const tbody = document.getElementById('tbody');
      tbody.innerHTML = '';
      document.getElementById('count').textContent = items.length;
      for (let i = 0; i < items.length; i++) {
        const it = items[i] || {};
        const tr = document.createElement('tr');
        tr.innerHTML = `
          <td><input type="checkbox" class="row-check" /></td>
          <td><input class="code" type="text" value="${escapeHtml(it.code || '')}" /></td>
          <td><input class="name" type="text" value="${escapeHtml(it.name || '')}" /></td>
          <td><textarea class="def" rows="2">${escapeHtml(it.definition || '')}</textarea></td>
          <td><input class="kw" type="text" value="${escapeHtml((it.keywords || []).join(', '))}" placeholder="逗号分隔: 关键词1, 关键词2" /></td>
          <td class="row-actions">
            <button class="secondary" onclick="toUpperCode(this)">CODE大写</button>
          </td>
        `;
        tbody.appendChild(tr);
      }
      // 绑定全选
      const master = document.getElementById('checkAll');
      master.checked = false;
      master.onchange = () => {
        document.querySelectorAll('.row-check').forEach(cb => cb.checked = master.checked);
      };
    }

    function toUpperCode(btn) {
      const row = btn.closest('tr');
      const code = row.querySelector('input.code');
      code.value = (code.value || '').trim().toUpperCase();
    }

    function setLoading(b) {
      document.querySelectorAll('button').forEach(bn => bn.disabled = b);
    }

    function collectSelectedRows() {
      const rows = Array.from(document.querySelectorAll('#tbody tr'));
      const selected = [];
      for (const r of rows) {
        const checked = r.querySelector('.row-check').checked;
        if (!checked) continue;
        const code = (r.querySelector('input.code').value || '').trim().toUpperCase();
        const name = (r.querySelector('input.name').value || '').trim();
        const definition = (r.querySelector('textarea.def').value || '').trim();
        const kwStr = (r.querySelector('input.kw').value || '').trim();
        const keywords = kwStr ? kwStr.split(',').map(s => s.trim()).filter(Boolean) : [];
        if (!code || !name) continue; // 跳过不完整项
        selected.push({ code, name, definition, keywords, is_active: 1 });
      }
      return selected;
    }

    function collectAllRows() {
      const rows = Array.from(document.querySelectorAll('#tbody tr'));
      const all = [];
      for (const r of rows) {
        const code = (r.querySelector('input.code').value || '').trim().toUpperCase();
        const name = (r.querySelector('input.name').value || '').trim();
        const definition = (r.querySelector('textarea.def').value || '').trim();
        const kwStr = (r.querySelector('input.kw').value || '').trim();
        const keywords = kwStr ? kwStr.split(',').map(s => s.trim()).filter(Boolean) : [];
        if (!code || !name) continue;
        all.push({ code, name, definition, keywords, is_active: 1 });
      }
      return all;
    }

    async function approveSelected() {
      const payload = collectSelectedRows();
      if (payload.length === 0) { alert('未选择或数据不完整（code/name 不能为空）'); return; }
      await doApprove(payload);
    }

    async function approveAll() {
      const payload = collectAllRows();
      if (payload.length === 0) { alert('没有可提交的数据'); return; }
      await doApprove(payload);
    }

    async function doApprove(payload) {
      setLoading(true);
      try {
        const res = await fetch('/api/taxonomy/approve', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(payload)
        });
        if (!res.ok) throw new Error('调用 /api/taxonomy/approve 失败');
        alert('已提交审核入库');
      } catch (e) {
        alert(e.message || e);
      } finally {
        setLoading(false);
      }
    }

    function escapeHtml(s) {
      return String(s)
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
    }
  </script>
</head>
<body>
  <h1>类目归纳审核</h1>
  <div class="toolbar">
    <label>
      样本条数：<input id="sampleSize" type="number" min="1" step="1" placeholder="留空按默认" />
    </label>
    <button onclick="runBuild()">触发归纳（build）</button>
    <span class="muted">已入库新增：<strong id="inserted">0</strong></span>
    <span class="muted counter">预览候选：<strong id="count">0</strong> 条</span>
  </div>
  <div class="notice">
    说明：点击“触发归纳”后，系统会将首轮归纳的类目直接入库；下表展示的是针对“难分类样本”的二次归纳候选，仅供审核。勾选或编辑后，点击“批准选中”或“批准全部”入库。
  </div>

  <div class="toolbar">
    <label><input id="checkAll" type="checkbox" /> 全选</label>
    <button class="secondary" onclick="approveSelected()">批准选中</button>
    <button onclick="approveAll()">批准全部</button>
  </div>

  <table>
    <thead>
      <tr>
        <th style="width: 48px;">选</th>
        <th style="width: 140px;">Code</th>
        <th style="width: 220px;">名称</th>
        <th>定义</th>
        <th style="width: 260px;">关键词（逗号分隔）</th>
        <th style="width: 110px;">操作</th>
      </tr>
    </thead>
    <tbody id="tbody"></tbody>
  </table>
</body>
</html>

